﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;

using ScintillaNet;
using Descriptions;
using LPMEDEditor;

namespace LPMEDEditor
{
    public class Factory : IDocumentsFactory
    {
        DomainModel domainModel;
        List<Document> documents_in_project = new List<Document>();
        MenuControl menuctrl;

        #region IDocumentsFactory Members

        public List<ICompilationUnit> GetCompilationUnits()
        {
            List<CompilationUnit> units = new List<CompilationUnit>();
            foreach (var lpmed in documents_in_project)
            {
              if (lpmed.IsCompile)
              {
                units.Add(new CompilationUnit(lpmed.Name, lpmed.LPMEDCode, this.domainModel, lpmed)); 
              }
            }
            return units.ConvertAll < ICompilationUnit>(val => val as ICompilationUnit) ;
        }

        public void Initialize(DomainModel model, Core.Logger.ILogger logger)
        {
          domainModel = model;
        }

        public ICodeEditor LoadExisting(string Path)
        {
            /*byte[] data = null;
            using (FileStream fs = File.Open(Path, FileMode.Open))
            {
                data = new byte[fs.Length];
                fs.Read(data, 0, (int)fs.Length);
            }

            doc.Document.RawText = data;*/
            if (!File.Exists(Path))
                return null;

            DocumentStorage docstg=Utility.DeserializeFromFile<DocumentStorage>(Path);

            Document doc = new Document(Path, docstg);
            documents_in_project.Add(doc);

            return doc;
        }

        public ICodeEditor New(NewCodeFileDialog dialog)
        {
            DocumentStorage docstg = new DocumentStorage { ModuleName = Path.GetFileNameWithoutExtension(dialog.FilePath),//*device.Name, DeviceName = "mp11"*/,
                                                           LPMEDText = "DEVICE " + "NoName" +Environment.NewLine+
                                                           "{"
                                                           +Environment.NewLine+"}"+Environment.NewLine+
                                                           "END."
                                                         };
            Document doc = new Document(dialog.FilePath,docstg);
            documents_in_project.Add(doc);

            return doc;
        }

        public void RemoveFromProject(ICodeEditor doc)
        {
            if(doc is Document)
                documents_in_project.Remove((Document)doc);
        }

        public List<ToolStripMenuItem> GetPluginMenuItems()
        {
            if(menuctrl==null)
                menuctrl = new MenuControl(this);

            List<ToolStripMenuItem> menu = new List<ToolStripMenuItem>();
            menu.Add(menuctrl.editToolStripMenu);
            menu.Add(menuctrl.viewStripMenuItem);
            return menu;
        }

        public NewCodeFileDialog GetNewCodeFileDialog(List<string> AddedModulesNames)
        {
          return new LPMEDNewCodeFileDialog(AddedModulesNames);
        }
        #endregion

        private Document ActiveDocument
        {
            get
            {
                foreach (var lpmed in documents_in_project)
                    if (lpmed.Visible)
                        return lpmed;
                return null;
            }
        }

        #region frmDocEvents

        /*internal void printToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.Document.Printing.Print();
        }

        internal void printPreviewToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.Document.Printing.PrintPreview();
        }*/

        internal void undoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.UndoRedo.Undo();
        }

        internal void redoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.UndoRedo.Redo();
        }

        internal void cutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Clipboard.Cut();
        }

        internal void copyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Clipboard.Copy();
        }

        internal void pasteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Clipboard.Paste();
        }

        internal void selectAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Selection.SelectAll();
        }

        internal void findToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.FindReplace.ShowFind();
        }

        internal void replaceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.FindReplace.ShowReplace();
        }

        internal void findInFilesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //	Coming someday...
        }

        internal void replaceInFilesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //	Coming someday...
        }

        internal void goToToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.GoTo.ShowGoToDialog();
        }

        internal void toggleBookmarkToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Lines.Current.AddMarker(0);
        }

        internal void previosBookmarkToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //	 I've got to redo this whole FindNextMarker/FindPreviousMarker Scheme
            Line l = ActiveDocument.ScDoc.Lines.Current.FindPreviousMarker(1);
            if (l != null)
                l.Goto();
        }

        internal void nextBookmarkToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //	 I've got to redo this whole FindNextMarker/FindPreviousMarker Scheme
            Line l = ActiveDocument.ScDoc.Lines.Current.FindNextMarker(1);
            if (l != null)
                l.Goto();
        }

        internal void clearBookmarsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Markers.DeleteAll(0);
        }

        internal void dropToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.DropMarkers.Drop();
        }

        internal void collectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.DropMarkers.Collect();
        }

        internal void makeUpperCaseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Commands.Execute(BindableCommand.UpperCase);
        }

        internal void makeLowerCaseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Commands.Execute(BindableCommand.LowerCase);
        }

        internal void commentStreamToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Commands.Execute(BindableCommand.StreamComment);
        }

        internal void commentLineToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Commands.Execute(BindableCommand.LineComment);
        }

        internal void uncommentLineToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Commands.Execute(BindableCommand.LineUncomment);
        }

        internal void autocompleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.AutoComplete.Show();
        }

        internal void insertSnippetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Snippets.ShowSnippetList();
        }

        internal void surroundWithToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Snippets.ShowSurroundWithList();
        }

        internal void whiteSpaceToolStripMenuItem_Click(object sender, EventArgs e)
        {
     /*       whiteSpaceToolStripMenuItem.Checked = !whiteSpaceToolStripMenuItem.Checked;

            if (whiteSpaceToolStripMenuItem.Checked)
            {
                ActiveDocument.ScDoc.WhiteSpace.Mode = WhiteSpaceMode.VisibleAlways;
            }
            else
            {
                ActiveDocument.ScDoc.WhiteSpace.Mode = WhiteSpaceMode.Invisible;
            }
      * */
        }

        internal void wordWrapToolStripMenuItem_Click(object sender, EventArgs e)
        {
            /*
            wordWrapToolStripMenuItem.Checked = !wordWrapToolStripMenuItem.Checked;

            if (wordWrapToolStripMenuItem.Checked)
            {
                ActiveDocument.ScDoc.LineWrap.Mode = WrapMode.Word;
            }
            else
            {
                ActiveDocument.ScDoc.LineWrap.Mode = WrapMode.None;
            }
             */
        }

        internal void endOfLineToolStripMenuItem_Click(object sender, EventArgs e)
        {
            /*
            endOfLineToolStripMenuItem.Checked = !endOfLineToolStripMenuItem.Checked;
            ActiveDocument.ScDoc.EndOfLine.IsVisible = endOfLineToolStripMenuItem.Checked;
             */ 
        }

        internal void zoomInToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Zoom++;
        }

        internal void zoomOutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Zoom--;
        }

        internal void resetZoomToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.Zoom = 0;
        }

        internal void lineNumbersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            /*lineNumbersToolStripMenuItem.Checked = !lineNumbersToolStripMenuItem.Checked;
            if (lineNumbersToolStripMenuItem.Checked)
                ActiveDocument.ScDoc.Margins.Margin0.Width = 35;
            else
                ActiveDocument.ScDoc.Margins.Margin0.Width = 0;
             */ 
        }

        internal void foldLevelToolStripMenuItem_Click(object sender, EventArgs e)
        {

            ActiveDocument.ScDoc.Lines.Current.FoldExpanded = true;
        }

        internal void unfoldLevelToolStripMenuItem_Click(object sender, EventArgs e)
        {

            ActiveDocument.ScDoc.Lines.Current.FoldExpanded = false;
        }

        internal void foldAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (Line l in ActiveDocument.ScDoc.Lines)
            {
                l.FoldExpanded = true;
            }
        }

        internal void unfoldAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (Line l in ActiveDocument.ScDoc.Lines)
            {
                l.FoldExpanded = false;
            }
        }

        internal void navigateForwardToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.DocumentNavigation.NavigateForward();
        }

        internal void navigateBackwardToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDocument.ScDoc.DocumentNavigation.NavigateBackward();
        }
        #endregion
    }

    internal class CompilationUnit : ICompilationUnit
    {
        public string Name { get; set; }
        internal string LPMED { get; set; }
        DomainModel domainModel;
        ICodeEditor editor;

        public CompilationUnit(string Name, string LPMEDCode, DomainModel domainModel, ICodeEditor editor)
        {
          this.Name = Name;
          this.LPMED = LPMEDCode;
          this.domainModel = domainModel;
          this.editor = editor;
        }

        public string Compile(out ErrorReport ErReport)
        {
            ErReport = new ErrorReport();
            var translator = new LPMEDLuaTranslator.LPMEDLuaTranslator(this.domainModel);

            ErReport.AddRange(translator.LPMEDstring_SintaxisAnalize(LPMED, editor));
            if (ErReport.Errors.Count != 0)
              return "";

            ErReport.AddRange(translator.LPMEDstring_SemanticAnalize(LPMED, editor));
            if (ErReport.Errors.Count != 0)
              return "";
            
            return LPMED;
        }
    }
}